#include "CGraphic.h"

CGraphic::CGraphic()
{

}

CGraphic::CGraphic(HWND hwnd, HINSTANCE hInstance, int width, int height, bool IsFullScreen)
{
	m_hwnd				=	hwnd;
	m_hInstance			=	hInstance;
	m_ScreenWidth		=	width;
	m_ScreenHeight		=	height;
	m_IsFullScreen		=	IsFullScreen;

	m_pD3dDevice		=	NULL;
	m_pD3d				=	NULL;

	m_pSpriteHandler	=	NULL;

	ZeroMemory( &m_PresentPara , sizeof(D3DPRESENT_PARAMETERS) );
}

CGraphic::~CGraphic()
{
	Release();
}

//--------------------------------------//
// Name : Release                       //
// Desc : Release all data , object ... //
//--------------------------------------//
void CGraphic::Release()
{
	if(m_pD3dDevice)
		m_pD3dDevice->Release();
	if(m_pD3d)
		m_pD3d->Release();
	if(m_pSpriteHandler)
		m_pSpriteHandler->Release();

	m_pD3dDevice		= NULL;
	m_pD3d				= NULL;
	m_hwnd				= NULL;
	m_hInstance			= NULL;
	m_pSpriteHandler	= NULL;

	ZeroMemory( &m_PresentPara , sizeof(D3DPRESENT_PARAMETERS) );
}

//----------------------------------------------------------------------//
// Name : FindDepthStencilFormat                                        //
// Desc : Use to find the best depth stencil format for create a device //
//----------------------------------------------------------------------//
D3DFORMAT CGraphic::FindDepthStencilFormat(ULONG AdapterOrdinal, D3DDISPLAYMODE Mode, D3DDEVTYPE DevType)
{
	// Check 32bit depth buffer available
	if (SUCCEEDED( m_pD3d->CheckDeviceFormat(AdapterOrdinal, DevType, Mode.Format, D3DUSAGE_DEPTHSTENCIL , D3DRTYPE_SURFACE , D3DFMT_D32 )))
	{
		if (SUCCEEDED( m_pD3d->CheckDepthStencilMatch ( AdapterOrdinal, DevType, Mode.Format, Mode.Format, D3DFMT_D32 ))) 
			return D3DFMT_D32;
		
	} 

	// Check 24bit depth buffer available
	if (SUCCEEDED( m_pD3d->CheckDeviceFormat(AdapterOrdinal, DevType, Mode.Format, D3DUSAGE_DEPTHSTENCIL , D3DRTYPE_SURFACE , D3DFMT_D24X8 )))
	{
		if (SUCCEEDED( m_pD3d->CheckDepthStencilMatch ( AdapterOrdinal, DevType, Mode.Format, Mode.Format, D3DFMT_D24X8 ))) 
			return D3DFMT_D24X8;
		
	} 

	// Check 16bit depth buffer available
	if (SUCCEEDED( m_pD3d->CheckDeviceFormat(AdapterOrdinal, DevType, Mode.Format, D3DUSAGE_DEPTHSTENCIL , D3DRTYPE_SURFACE , D3DFMT_D16 )))
	{
		if (SUCCEEDED( m_pD3d->CheckDepthStencilMatch ( AdapterOrdinal, DevType, Mode.Format, Mode.Format, D3DFMT_D16 ))) 
			return D3DFMT_D16;
		
	} 
	// No depth buffer supported
	
	return D3DFMT_UNKNOWN;
}

//---------------------------------//
// Name : Init                     //
// Desc : Create d3d and d3dDevice //
//---------------------------------//
bool CGraphic::Init()
{
	D3DPRESENT_PARAMETERS	pPresent;
	D3DCAPS9				caps;
	D3DDISPLAYMODE			currentMode;

	if(NULL==(m_pD3d=Direct3DCreate9(D3D_SDK_VERSION)))
	{
		return false;
	}
	ZeroMemory(&pPresent,sizeof(pPresent));

	m_pD3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&currentMode);

	pPresent.BackBufferFormat			=	currentMode.Format;
	pPresent.SwapEffect					=	D3DSWAPEFFECT_DISCARD;
	pPresent.Windowed					=	!m_IsFullScreen;
	pPresent.AutoDepthStencilFormat		=	FindDepthStencilFormat(D3DADAPTER_DEFAULT,currentMode,D3DDEVTYPE_HAL);
	pPresent.EnableAutoDepthStencil		=	true;
	pPresent.PresentationInterval		=	D3DPRESENT_INTERVAL_IMMEDIATE;

	pPresent.BackBufferCount			=	1;
	pPresent.BackBufferHeight			=	m_ScreenHeight;
	pPresent.BackBufferWidth			=	m_ScreenWidth;
	pPresent.hDeviceWindow				=	m_hwnd;
	pPresent.FullScreen_RefreshRateInHz =	D3DPRESENT_RATE_DEFAULT;

	unsigned long ulFlag = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	ZeroMemory(&caps,sizeof(D3DCAPS9));
	m_pD3d->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&caps);

	if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		ulFlag = D3DCREATE_HARDWARE_VERTEXPROCESSING;

	if (FAILED(m_pD3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hwnd, ulFlag, &pPresent, &m_pD3dDevice)))
	{

		pPresent.AutoDepthStencilFormat = FindDepthStencilFormat(D3DADAPTER_DEFAULT , currentMode , D3DDEVTYPE_REF);
		ZeroMemory( &caps , sizeof(D3DCAPS9) );

		ulFlag = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

		m_pD3d->GetDeviceCaps(D3DADAPTER_DEFAULT , D3DDEVTYPE_REF , &caps);

		if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
			ulFlag = D3DCREATE_HARDWARE_VERTEXPROCESSING;

		if(FAILED(m_pD3d->CreateDevice(D3DADAPTER_DEFAULT , D3DDEVTYPE_REF , m_hwnd , ulFlag , &pPresent , &m_pD3dDevice)))
		{
			return false;
		}
	}

	m_PresentPara	=	pPresent;


	return true;
}	


//----------------------------------------------------------------//
// Name : InitSpriteHandler                                       //
// Desc : Use to init a sprite handle for drawing texture etc ... //
//----------------------------------------------------------------//
bool CGraphic::InitSpriteHandler()
{
	if(!m_pD3dDevice)
		return false;

	if(FAILED(D3DXCreateSprite(m_pD3dDevice , &m_pSpriteHandler)))
		return false;

	return true;
}


//-------------------------//
// Name : BeginRender      //
// Desc : Begin for render //
//-------------------------//
void CGraphic::BeginRender()
{
	if(m_pD3dDevice==NULL)
		return;
	m_pD3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0xffffffff,1.0f,0);
	m_pD3dDevice->BeginScene();
}

//----------------------------------------------------------------------------------//
// Name : EndRender                                                                 //
// Desc : End render , after this call must Present to show up what you have render //
//----------------------------------------------------------------------------------//
void CGraphic::EndRender()
{
	m_pD3dDevice->EndScene();
}

//-------------------------------------------//
// Name : ClearScreen                        //
// Desc : Clear the back buffer and Z buffer //
//-------------------------------------------//
void CGraphic::ClearScreen()
{
	m_pD3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(200,0,0),1.0f,0);
}

//-----------------------------------------//
// Name : GetDevice                        //
// Desc : return the pointer of the device //
//-----------------------------------------//
LPDIRECT3DDEVICE9	CGraphic::GetDevice() const
{
	if(!m_pD3dDevice)
		return NULL;
	
	return m_pD3dDevice;
}


//------------------------------------------------//
// Name : GetSpriteHandler                        //
// Desc : return the pointer of the LPD3DXSPRITE  //
//		   which use to handle sprite             //
//------------------------------------------------//
LPD3DXSPRITE	CGraphic::GetSpriteHandler() const
{
	if(!m_pSpriteHandler)
		return NULL;

	return m_pSpriteHandler;
}